package main

import (
	"fmt"
	"reflect"
)

func reflectDemo() {
	var age interface{} = 25

	fmt.Printf("原始接口类型变量类型为：%T，值为：%v \n", age, age)

	typeOf := reflect.TypeOf(age)
	valeuOf := reflect.ValueOf(age)

	fmt.Printf("接口类型转换为反射对象，Type对象的类型为：%T\n", typeOf)
	fmt.Printf("接口类型转换为反射对象，Value对象的类型为：%T\n", valeuOf)

	//原始接口类型变量类型为：int，值为：25
	//接口类型转换为反射对象，Type对象的类型为：*reflect.rtype
	//接口类型转换为反射对象，Value对象的类型为：reflect.Value

	i := valeuOf.Interface()
	fmt.Printf("反射对象转换为接口类型，i的类型为：%T，值为：%v\n", i, i)
	//反射对象转换为接口类型，i的类型为：int，值为：25

	isCanSet := valeuOf.CanSet()
	fmt.Println(isCanSet) // false
}

func reflectWritable() {
	var name interface{} = "天龙山"
	nameVal1 := reflect.ValueOf(&name)
	nameVal2 := nameVal1.Elem()
	fmt.Printf("nameValWritable is can set? %v\n", nameVal1.CanSet()) // nameValWritable is can set? false
	fmt.Printf("nameValWritable is can set? %v\n", nameVal2.CanSet()) // nameValWritable is can set? true
}

func reflectKind() {
	type Profile struct {
		name   string
		age    int
		gender string
	}

	profile := Profile{}

	//值传递
	profileType := reflect.TypeOf(profile)
	fmt.Println("Type：", profileType)        //Type： main.Profile
	fmt.Println("Kind：", profileType.Kind()) //Kind： struct

	//指针传递
	profileTypePtr := reflect.TypeOf(&profile)
	fmt.Println("&profile Type", profileTypePtr)        //&profile Type *main.Profile
	fmt.Println("&profile Kind", profileTypePtr.Kind()) //&profile Kind ptr
	//Elem：获取指针指向的内存数据
	fmt.Println("profile Type", profileTypePtr.Elem())        //profile Type main.Profile
	fmt.Println("profile Kind", profileTypePtr.Elem().Kind()) //profile Kind struct

	profileValPtr := reflect.ValueOf(&profile)
	fmt.Println("&profile Type", profileValPtr.Type())       //&profile Type *main.Profile
	fmt.Println("&profile Kind", profileValPtr.Kind())       //&profile Kind ptr
	fmt.Println("profile Type", profileValPtr.Elem().Type()) //profile Type main.Profile
	fmt.Println("profile Kind", profileValPtr.Elem().Kind()) //profile Kind struct
}

func reflectTypeConversion(dataVal reflect.Value) {
	switch dataVal.Kind() {
	case reflect.Int:
		dataInt := dataVal.Int()
		fmt.Printf("Type:%T，Value:%v\n", dataInt, dataInt)
	case reflect.Float64, reflect.Float32:
		dataFloat := dataVal.Float()
		fmt.Printf("Type:%T，Value:%v\n", dataFloat, dataFloat)
	case reflect.String:
		dataString := dataVal.String()
		fmt.Printf("Type:%T，Value:%v\n", dataString, dataString)
	case reflect.Bool:
		dataBool := dataVal.Bool()
		fmt.Printf("Type:%T，Value:%v\n", dataBool, dataBool)
	case reflect.Ptr:
		dataPointer := dataVal.Pointer()
		fmt.Printf("Type:%T，Value:%v\n", dataPointer, dataPointer)
	case reflect.Interface:
		dataInterface := dataVal.Interface()
		fmt.Printf("Type:%T，Value:%v11", dataInterface, dataInterface)
	}
}

func reflectSlice() {
	var numberSlice []int = []int{1, 2}
	value := reflect.ValueOf(numberSlice)
	value1 := value.Slice(0, 2)
	fmt.Printf("转换前，type：%T，value：%v \n", value, value1) //转换前，type：reflect.Value，value：[1 2]
	fmt.Printf("转换后，type：%T，value：%v \n", value, value1) //转换后，type：reflect.Value，value：[1 2]

	//更新切片
	numberValPointer := reflect.ValueOf(&numberSlice)
	numberPointerVal := numberValPointer.Elem()
	numberPointerVal.Set(reflect.Append(numberPointerVal, reflect.ValueOf(3)))
	fmt.Println(numberSlice)      // [1 2 3]
	fmt.Println(len(numberSlice)) // 3
}

type Person struct {
	name   string
	age    int
	gender string
}

func (p Person) SayBye() string {
	return "Bye"
}

func (p Person) SayHello() string {
	return "Hello"
}

func (p Person) SetAge(age int) {
	fmt.Printf("Hello, my name is %s and i'm %d years old.", p.name, age)
}

func reflectStruct() {
	//反射struct属性
	xietian := Person{"邪天", 10800, "male"}
	xietianVal := reflect.ValueOf(xietian)
	//获取字段个数
	fields := xietianVal.NumField()
	fmt.Println("字段个数：", fields) // 3
	//遍历所有的字段值
	for x := 0; x < fields; x++ {
		fmt.Println("第", x, "字段:", xietianVal.Field(x))
		//第 0 字段: 邪天
		//第 1 字段: 10800
		//第 2 字段: male
	}

	//获取函数个数
	xietianType := reflect.TypeOf(xietian)
	methods := xietianType.NumMethod()
	fmt.Println("方法数(可导出)：", methods) //方法数(可导出)： 2
	//遍历所有方法名
	for x := 0; x < methods; x++ {
		fmt.Printf("第 %d 个方法： %v \n", x+1, xietianType.Method(x).Name)
		//第 1 个方法： SayBye
		//第 2 个方法： SayHello
	}

	//动态调用函数(使用索引且无参数)
	xietianValPointer := reflect.ValueOf(&xietian)
	for x := 0; x < methods; x++ {

		if xietianType.Method(x).Func.IsNil() {
			fmt.Printf("调用第 %d 个方法：%v ，调用结果：%v \n",
				x+1,
				xietianType.Method(x).Name,
				xietianValPointer.Elem().Method(x).Call(nil),
			)
			//调用第 1 个方法：SayBye ，调用结果：[Bye]
			//调用第 2 个方法：SayHello ，调用结果：[Hello]
		}

	}

	//动态调用函数(使用函数名且无参数)
	sayByeRes := xietianValPointer.MethodByName("SayBye").Call(nil)
	fmt.Printf("Method SayBye execute result：%v \n", sayByeRes) //Method SayBye execute result：[Bye]

	//动态调用函数(使用函数名且有参数)
	age := reflect.ValueOf(27)
	methodParams := []reflect.Value{age}
	xietianValPointer.MethodByName("SetAge").Call(methodParams) //Hello, my name is 邪天 and i'm 27 years old.
}
